﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            
            Bank bank = new Bank("宇宙第一银行");
            bank.Start();
           
        }
        
    }


    public class Meesage {
        public static void Show(string msg) {
            Console.WriteLine(msg);
        }
        public static string GetInput() {
            return Console.ReadLine();// 输入字符
        }

        //输入字符串转成int,如果不是数字,需要重复输入,直到读取到int
        public static int GetInputIntger(string error) {
            var input = Console.ReadLine();
            try {
                return int.Parse(input);
            } catch (Exception) {
                Show(error);
                return GetInputIntger(error);
            }
        }

        public static int GetInputIntger(Func<int,bool> fun, string error) {
            var result = GetInputIntger(error);
            while (!fun(result)) {
                result = GetInputIntger(error);
            }
            return result;
        }
    }
    public class Log {
        public static void Debug(string msg) {
            Console.WriteLine("debug:"+msg);
        }

        public static void Info(string msg) {
            Console.WriteLine("info:" + msg);
        }
        public static void Waring(string msg) {
            Console.WriteLine("warn:" + msg);
        }
        public static void Error(string msg) {
            Console.WriteLine("error:" + msg);
        }
    }
    //Credit card 信用卡, Debit card储蓄卡

    //储蓄卡
    public sealed class DebitCard : Account {

        public override bool SaveMoney(int num) {
            Balance += num;
            Log.Info($"账户:{Id}存入:{num}元,余额:{Balance}元");
            return true;
        }

        public override bool WithdrawMoney(int num) {
            if (num > Balance) {
                Log.Info($"账户:{Id}取出:{num}元操作失败!余额:{Balance}元");
                return false;
            }
            Balance -= num;
            Log.Info($"账户:{Id}取出:{num}元,余额:{Balance}元");
            return true;
        }
    }
    //信用卡
    public sealed class CreditCard : Account {
        //最大信用额度
        public int CreditMax { set; get; }
        //当前剩余信用额度(可用)
        public int CreditBalance { set; get; }
        public CreditCard(int credit) : base() {
            this.CreditMax = this.CreditBalance = credit;
        }


        /**
         * 取钱
         * 1. 现金余额充足,直接扣现金
         * 2. 现金余额大于0,但是小于要取的金额,先扣除现金余额,再扣除授信余额.如果授信余额不够,取出失败
         * 3. 现金余额为0,扣除授信余额.如果授信余额不够,取出失败
         */
        public override bool WithdrawMoney( int num) {

            if (Balance >= num) {
                Balance -= num;
                LogSuccess(num, true);
                return true;
            }
            if (Balance > 0) {
                //余额不够扣,先扣现金余额,再扣可用额度
                var tmp = num - Balance;
                if (CreditBalance < tmp) {
                    //额度不够,取钱失败
                    LogFail(num, true);
                    return false;
                }
                Balance = 0;
                CreditBalance -= tmp;
                LogSuccess(num, true);
                return true;
            }
            if (CreditBalance < num) {
                //额度不够,取钱失败
                LogFail(num, true);
                return false;
            }
            CreditBalance -= num;
            LogSuccess(num, true);
            return true;

        }
        /**
         * 存钱
         * 1. 如果可用额度与最大额度的相差值大于充值金额,直接加可用额度
         * 2. 如果可用额度小于最大额度且相差值小于充值金额,先把可用额度加到最大额度,再加现金余额
         * 3. 如果可用额度等于最大额度,直接加现金余额
         */
        public override bool SaveMoney(int num) {
            var tmp = CreditMax - CreditBalance;
            if (tmp < 0) {
                Log.Error("存钱失败,系统异常,可用额度竟然大于最大额度!");
                return false;
            }
            if (tmp > num) {
                CreditBalance += num;
            } else if (tmp <= num) {
                CreditBalance = CreditMax;
                Balance += (num - tmp);
            } else if (tmp == 0) {
                Balance += num;
            }
            LogSuccess(num, false);
            return true;
        }
        private void LogSuccess(int num,bool withdraw) {
            Log.Info($"账户:{Id}{(withdraw ? "取出" : "存入")}:{num}元,现金余额:{Balance}元,最大额度:{CreditMax},可用额度:{CreditBalance}元,已用额度:{CreditMax - CreditBalance}");
        }
        private void LogFail(int num, bool withdraw) {
            Log.Info($"账户:{Id}尝试{(withdraw ? "取出" : "存入")}:{num}元,操作失败!现金余额:{Balance}元,最大额度:{CreditMax},可用额度:{CreditBalance}元,已用额度:{CreditMax - CreditBalance}");
        }


    }
    public abstract class Account {
        public int Id { set; get; }
        public int Pwd { set; get; }
        //余额(现金)
        public int Balance { set; get; }

        //取钱
        public abstract bool WithdrawMoney(int num);
        //存钱
        public abstract bool SaveMoney(int num);


        ////取钱
        //public void WithdrawMoney(int num) {
        //    Balance -= num;
        //    Log.Info($"账户:{Id}取出:{num}元,余额:{Balance}元");
        //}

        //public void SaveMoney(int num) {
        //    Balance += num;
        //    Log.Info($"账户:{Id}存入:{num}元,余额:{Balance}元");
        //}
    }



    public class Bank {
        //管理员id
        private int manageId=123456;
        //管理员密码
        private int managePwd=654321;
        private readonly string name;
        public Bank(string name) { this.name = name; }
        private bool start;
        private Dictionary<int, Account> accounts = new Dictionary<int, Account>();
        private void AddDebitCard(int id, int pwd, int money) {
            AddAccount(new DebitCard() { Id=id,Pwd=pwd,Balance=money});
        }
        private void AddCreditCard(int id, int pwd, int creditMax) {
            AddAccount(new CreditCard(creditMax) { Id = id, Pwd = pwd });
        }

        private bool AddAccount(Account account) {
            if(account is DebitCard) {
                Log.Info($"银行新增储蓄卡账户成功:id={account.Id},money={account.Balance},pwd={account.Pwd}");
            } else {
                var creditCard=account as CreditCard;
                Log.Info($"银行新增信用卡账户成功:id={creditCard.Id},money={creditCard.CreditMax},pwd={account.Pwd}");
            }
            accounts.Add(account.Id, account);
            return true;
        }
        private bool CheckId(int id) {
            if (accounts.ContainsKey(id)) {
                Log.Waring($"银行已存在账户:{id},不需要再次添加");
                return false;
            }
            return true;
        }
        //账户登录校验
        public Account AccountLogin(int id,int pwd) {
            if (!accounts.ContainsKey(id))
                return null;
            if (accounts[id].Pwd == pwd)
                return accounts[id];
            return null;
        }
        //工作人员登录校验
        public bool WorkerLogin(int id, int pwd) {
            return manageId == id && managePwd == pwd;
        }

        public void Start() {
            start = true;
            PageOpen();
        }
        public void Close() {
            start = false;
        }
        public void PageOpen() {
            while (start) {
                Meesage.Show($"****************欢迎光临{this.name}!****************");
                Meesage.Show("1: 工作人员入口;     2: 客户入口;");
                switch (Meesage.GetInput()) {
                    case "1":
                        if (!PageWorkerLogin()) {
                            Meesage.Show("密码或账号错误,工作人员登录失败!");
                            continue;
                        }
                        PageWork();
                        break;
                    case "2":
                        Account account = PageAccountLogin();
                        if (account==null) {
                            Meesage.Show("密码或账号错误,登录失败!");
                            continue;
                        }
                        PageATM(account);
                        break;
                    default:
                        break;
                }
            }
            Meesage.Show("银行工作人员已下班");
        }
        //客户去ATM机页面
        private void PageATM(Account account) {
            while (true) {
                Meesage.Show("1: 余额查询;     2: 取钱;    3:  存钱     4:  退出");
                switch (Meesage.GetInput()) {
                    case "1":
                        if (account is DebitCard)
                            Meesage.Show($"您的储蓄账号:{account.Id},余额:{account.Balance}元");
                        else {
                            var creditCard = account as CreditCard;
                            Meesage.Show($"您的信用卡账号:{creditCard.Id},现金余额:{creditCard.Balance}元,最大额度:{creditCard.CreditMax},可用额度:{creditCard.CreditBalance}元,已用额度:{creditCard.CreditMax - creditCard.CreditBalance}");
                        }
                        break;
                    case "2":
                        PageATMWithdrawMoney(account);
                        break;
                    case "3":
                        PageATMSaveMoney(account);
                        break;
                    case "4":
                        return;
                    default:
                        break;
                }
            }

        }

        private void PageATMSaveMoney(Account account) {
            Meesage.Show("请输入要存入的金额");
            var num = Meesage.GetInputIntger("请输入要存入的金额");
            if (num < 1) {
                Meesage.Show("存入金额不能小于1");
                PageATMWithdrawMoney(account);
                return;
            }
            
            account.SaveMoney(num);
            return;

        }
        private void PageATMWithdrawMoney(Account account) {
            Meesage.Show("请输入要取出的金额");
            var num = Meesage.GetInputIntger("请输入要取出的金额");
            if (num<1) {
                Meesage.Show("取出金额不能小于1");
                PageATMWithdrawMoney(account);
                return;
            }
            if(account is DebitCard) {
                if (num > account.Balance) {
                    Meesage.Show($"取出金额不能大于余额:{account.Balance}元");
                    PageATMWithdrawMoney(account);
                    return;
                }
            } else {
                var creditCard=account as CreditCard;
                var credit =creditCard.Balance + creditCard.CreditBalance;
                if (num > credit) {
                    Meesage.Show($"取出金额不能大于可用额度:{credit}元");
                    PageATMWithdrawMoney(account);
                    return;
                }
            }

            account.WithdrawMoney(num);
            return;

        }
        private Account PageAccountLogin() {
            Meesage.Show("请输入银行账号");
            var id = Meesage.GetInputIntger("请输入银行账号(3位数字)");
            Meesage.Show("请输入账号密码");
            var pwd = Meesage.GetInputIntger("请输入账号密码(6位数字)");
            return AccountLogin(id,pwd);
        }
        //工作人员登录页面
        private bool PageWorkerLogin() {
            Meesage.Show("请输入工作账号");
            var id=Meesage.GetInputIntger("请输入工作账号(n位数字)");
            Meesage.Show("请输入工作账号密码");
            var pwd=Meesage.GetInputIntger("请输入工作账号密码(n位数字)");
            return WorkerLogin(id, pwd);
        }
        //工作人员去工作页面,添加账户,下班(关闭银行)
        private void PageWork() {
            while (true) {
                Meesage.Show("1: 新增储蓄卡;     2: 新增信用卡;    3:  休息一下       4:下班");
                switch (Meesage.GetInput()) {
                    case "1":
                        PageWorkAddDebitCard();
                        break;
                    case "2":
                        PageWorkAddCreditCard();
                        break;
                    case "3":
                        return;
                    case "4":
                        Close();
                        return;
                    default:
                        break;
                }
            }
            
        }
        //
        //新增信用卡
        private void PageWorkAddCreditCard() {

            Meesage.Show("请输入信用卡账号(3位数字)");
            var id = Meesage.GetInputIntger("请输入信用卡账号(3位数字)");
            if (!CheckId(id)) {
                return;
            }
            Meesage.Show("请输入账号密码(6位数字)");
            var pwd = Meesage.GetInputIntger("请输入账号密码(6位数字)");
            Meesage.Show("请输入授信额度(整数)");
            var creditMax = Meesage.GetInputIntger("请输入授信额度(整数)");
            AddCreditCard(id, pwd, creditMax);
        }



        //新增储蓄卡
        private void PageWorkAddDebitCard() {
            
            Meesage.Show("请输入储蓄卡账号(3位数字)");
            var id=Meesage.GetInputIntger("请输入储蓄卡账号(3位数字)");
            if (!CheckId(id)) {
                return;
            }
            Meesage.Show("请输入账号密码(6位数字)");
            var pwd = Meesage.GetInputIntger("请输入账号密码(6位数字)");
            Meesage.Show("请输入账号初始余额(整数)");
            var money = Meesage.GetInputIntger("请输入账号初始余额(整数)");
            AddDebitCard(id, pwd, money);
        }

 
    }
}
